/*              Copyright(c) 2008 Dave Sexton              *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.ComponentModel;

namespace DaveSexton.Sandcastle
{
	[DisplayName("Import mappings"), Description("Imports mappings or provider configuration from another file.")]
	public sealed class FileUrlMappingProvider : UrlMappingProvider
	{
		#region Public Properties
		public string File
		{
			get
			{
				return file;
			}
		}

		public string NestedProviderType
		{
			get
			{
				return providerType;
			}
		}

		public string NestedProviderAssembly
		{
			get
			{
				return providerAssembly;
			}
		}

		public UrlMappingProvider NestedProvider
		{
			get
			{
				return provider;
			}
		}

		public string ConfigurationFromFile
		{
			get
			{
				return configurationFromFile;
			}
			set
			{
				configurationFromFile = (string.IsNullOrEmpty(value)) ? null : value;
			}
		}
		#endregion

		#region Private / Protected
		private string configurationFromFile;
		private readonly UrlMappingProvider provider;
		private readonly string file, providerType, providerAssembly;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="FileUrlMappingProvider" /> class.
		/// </summary>
		public FileUrlMappingProvider(string rootPath, string file)
		{
			if (string.IsNullOrEmpty(file))
				throw new ArgumentException(Resources.Errors.NullOrEmpty, "file");

			this.file = file;
			provider = XmlUrlMappingProvider.Instance;

			configurationFromFile = LoadXmlConfigurationFromFile(rootPath, file);
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="FileUrlMappingProvider" /> class.
		/// </summary>
		public FileUrlMappingProvider(string rootPath, string file, string providerType, string providerAssembly)
		{
			if (string.IsNullOrEmpty(file))
				throw new ArgumentException(Resources.Errors.NullOrEmpty, "file");

			if (string.IsNullOrEmpty(providerType))
				throw new ArgumentException(Resources.Errors.NullOrEmpty, "providerType");

			this.file = file;
			this.providerType = providerType;
			this.providerAssembly = providerAssembly;

			provider = UrlMappingProvider.GetProvider(providerType, providerAssembly);

			configurationFromFile = LoadXmlConfigurationFromFile(rootPath, file);
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="FileUrlMappingProvider" /> class for editor support.
		/// </summary>
		internal FileUrlMappingProvider(string rootPath, string file, string configuration)
		{
			if (string.IsNullOrEmpty(file))
				throw new ArgumentException(Resources.Errors.NullOrEmpty, "file");

			this.file = file;
			provider = XmlUrlMappingProvider.Instance;

			if (string.IsNullOrEmpty(configuration))
				configurationFromFile = LoadXmlConfigurationFromFile(rootPath, file);
			else
				configurationFromFile = configuration;
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="FileUrlMappingProvider" /> class for editor support.
		/// </summary>
		internal FileUrlMappingProvider(string rootPath, string file, string providerType, string providerAssembly, string configuration)
		{
			if (string.IsNullOrEmpty(file))
				throw new ArgumentException(Resources.Errors.NullOrEmpty, "file");

			if (string.IsNullOrEmpty(providerType))
				throw new ArgumentException(Resources.Errors.NullOrEmpty, "providerType");

			this.file = file;
			this.providerType = providerType;
			this.providerAssembly = providerAssembly;

			provider = UrlMappingProvider.GetProvider(providerType, providerAssembly);

			if (string.IsNullOrEmpty(configuration))
				configurationFromFile = LoadXmlConfigurationFromFile(rootPath, file);
			else
				configurationFromFile = configuration;
		}
		#endregion
		
		#region Methods
		public static string FormatFilePath(string rootPath, string file)
		{
			if (string.IsNullOrEmpty(file))
				return rootPath ?? string.Empty;

			file = Environment.ExpandEnvironmentVariables(file);

			if (!System.IO.Path.IsPathRooted(file))
				file = System.IO.Path.Combine(rootPath, file);

			return file;
		}

		[System.Diagnostics.DebuggerHidden]
		private static string LoadXmlConfigurationFromFile(string rootPath, string file)
		{
			try
			{
				XmlDocument document = new XmlDocument();
				document.PreserveWhitespace = true;
				document.Load(FormatFilePath(rootPath, file));

				return document.OuterXml;
			}
			catch (System.IO.FileNotFoundException) { }
			catch (System.IO.DirectoryNotFoundException) { }

			return null;
		}

		public override IEnumerable<UrlMapping> GetMappings(UrlMappingGroup group, string configuration)
		{
			XmlDocument document = new XmlDocument();
			document.PreserveWhitespace = true;
			document.LoadXml(configurationFromFile ?? "<config/>");

			return provider.GetMappings(group, document.DocumentElement.OuterXml);
		}

		public override System.Windows.Forms.Control GetEditor(UrlMappingGroup group, string configuration)
		{
			// NOTE: Inner XML (the configuration argument) is always ignored when the file attribute is specified on a mapping group

			XmlDocument document = new XmlDocument();
			document.PreserveWhitespace = true;
			document.LoadXml(configurationFromFile ?? "<config/>");

			return provider.GetEditor(group, document.DocumentElement.InnerXml);
		}

		public override string GetEditorConfiguration(UrlMappingGroup group, System.Windows.Forms.Control control)
		{
			return provider.GetEditorConfiguration(group, control);
		}
		#endregion
	}
}
